<?php
/**
 * Created By: ST2
 * Created on 2014-08-26 13:32:55
 * author: yongchao.yu@kunlun-inc.com
 * coding: utf-8
*/
namespace Melon\Database\Driver;

use Melon\Exception;
defined('IN_MELON') or die('Permission denied');

class DbPdo extends Mysql {

	static protected $_linked = null; //是否连接
	private $PDOStatement = null; //预处理

	public function __construct( $config = array() ) {
		if (is_null(self::$_linked)) {
			$db_user = $config['username'];
			$db_passwd = $config['password'];
			$db_charset = $config['charset'];
			$this->options['prefix'] = isset($config['prefix']) ? $config['prefix'] : '';
			$dsn = "mysql:host=" . $config['host'] . ';dbname=' . $config['dbname'];

			$link = new \PDO( $dsn, $db_user, $db_passwd );

			if ( ! $link ) {
				\Melon::throwException( '数据连接失败' );
			} else {
				self::$_linked = $link;
				$link->exec( 'SET NAMES ' . $db_charset );
			}
			$this->linkID = $link;
			return $this->linkID;
		}
	}

	/**
	 * 获取最后一次插入ID
	 * @return [type] [description]
	 */
	public function getInsertId() {
		return $this->linkID->lastInsertId();
	}

	/**
	 * 获取影响的行数
	 * @return [type] [description]
	 */
	public function getAffectedRows() {
		return $this->numRows;
	}

	/**
	 * 执行一个语句
	 * @param  string $sql [description]
	 * @return [type]      [description]
	 */
	public function execute( $sql = '', $bind = array() ) {
		if ( ! $this->linkID ) return false;
		//查询的sql语句
		$sql = empty( $sql ) ? $this->queryStr : $sql;
		//释放前次的查询结果
		if ( is_resource( $this->linkID ) ) {	$this->free();	}
		$this->PDOStatement = $this->linkID->prepare($sql);

		//预处理失败
		if ( false === $this->PDOStatement ) {
			$this->error();
			return false;
		}

		$this->queryID = $this->PDOStatement->execute( $bind );
		//执行SQL失败
		if ( false === $this->queryID ) {
			$this->error();
			return false;
		} 

		$this->numRows = $this->PDOStatement->rowCount();
		return $this->numRows;
	}

	/**
	 * 查询符合条件的所有记录
	 * @param  [type]  $where [description]
	 * @param  string  $field [description]
	 * @param  [type]  $table [description]
	 * @param  boolean $all   [description]
	 * @return [type]         [description]
	 */
	public function findAll( $table = null, $where = null, $field = '*', $all = true) {

		$this->options['where'] = isset($this->options['where']) ? $this->options['where'] : $where;
		$this->options['field'] = isset($this->options['field']) ? $this->options['field'] : $field;
		$this->options['table'] = is_null($table) ? $this->table : $this->options['prefix'] . $table;

		 $sql = "SELECT {$this->options['field']} FROM `{$this->options['table']}` ";  
        $sql .= isset($this->options['join']) ? ' LEFT JOIN '.$this->options['join']: '';  
        $sql .= isset($this->options['where']) ? ' WHERE '.$this->options['where']: '';  
        $sql .= isset($this->options['group']) ? ' GROUP BY '.$this->options['group']: '';  
        $sql .= isset($this->options['having']) ? ' HAVING '.$this->options['having']: '';  
        $sql .= isset($this->options['order']) ? ' ORDER BY '.$this->options['order']: '';  
        $sql .= isset($this->options['limit']) ? ' LIMIT '.$this->options['limit']: '';  
        $this->queryStr = $sql;
        $row = null;
        $this->execute();
        $row = $all === true ? $this->PDOStatement->fetchAll(\PDO::FETCH_ASSOC) : $this->PDOStatement->fetch();
        return $row ? $row : false;

	}

	/**
	 * 查询符合提交的一条记录
	 * @param  [type] $where [查询条件]
	 * @param  string $field [查询字段]
	 * @param  string $talbe [表]
	 * @return [type]        [description]
	 */
	public function find( $table = null , $where = null, $field='*' ) {
		return $this->findAll($table, $where, $field, false);
	}

	/**
	 * 插入数据
	 * @param  [type]  $data    [插入的数据]
	 * @param  [type]  $table   [表名]
	 * @param  boolean $replace [description]
	 * @return [type]           [description]
	 */
	public function insert( $data, $table = null, $replace = false ) {
		$table = is_null( $table ) ? $this->table : $table;
		$sql = ($replace?'REPLACE':'INSERT'). " INTO `{$table}`";
		$fields = $values = $bindvalues = array();
		$field = $value = '';
		//遍历记录, 格式化字段名称与值
		foreach($data as $key => $val){
		    $fields[] = $this->parseKey($key);
		    $values[] = $val;
		    $bindvalues[] = '?';
		}

		$field = implode(',', $fields);
		$value = implode(',', $bindvalues);

		unset($fields, $prevalues);
		$sql .= "({$field}) VALUES({$value})";
		echo $sql;
		$this->execute($sql, $values);
		return $this->getInsertId();
	}

		/**
	 * 删除记录
	 * @param  [type] $table [表名]
	 * @param  [type] $where [条件]
	 * @return [type]        [影响行数]
	 */
	public function delete( $table = null, $where = null ) {
		$this->table = is_null($table) ? $this->table : $this->options['prefix'].$table;
		$where = is_null($where) ? (isset($this->options['where']) ? $this->options['where'] : null ) : $where;
		
		$this->queryStr = "DELETE FROM `{$this->table}` WHERE {$where}";
		//为了安全
		if ( is_null($where) && ! isset( $this->options['where'] ) ) {
			$this->error();
			return false;
		}

		return $this->linkID->exec($this->queryStr);
	}

	/**
	 * 数据更新  目前只支持数组
	 * @param  [type] $data  [更新数据]
	 * @param  [type] $where [where条件]
	 * @param  [type] $table [表名]
	 * @return [type]        [description]
	 */
	public function update( $data, $where = null, $table = null ) {
		$table = is_null($table) ? $this->table : $table;
		$where = is_null($where) ? @$this->options['where'] : $where;
		$sql = "UPDATE `{$table}` SET ";
		$values = $bindValues = array();
		foreach($data as $key => $val){  
            $values[] = $val;
            $bindValues[] = $this->parseKey($key) . " = ?";
        }

        $value = implode(',', $bindValues);
        $wbindvalues = $wvalues = array();
        if (is_array($where)) {
        	foreach ($where as $wkey => $wval) {
        		$wbindvalues[] = $this->parseKey($wkey) . " = ?";
        		$wvalues[] = $wval;
        	}
        }
        $this->queryStr = $sql.$value . " WHERE " . implode(',', $wbindvalues);
        $bind = array_merge($values, $wvalues);
        $this->execute($this->queryStr, $bind);
        return $this->getAffectedRows();
	}

    /**
     * 数据库错误信息
     * 并显示当前的SQL语句
     * @access public
     * @return string
     */
	public function error() {
		$errorInfo = $this->linkID->errorInfo();
		$this->error = $this->linkID->errorCode().':'. $errorInfo[2];
        if('' != $this->queryStr){
            $this->error .= "\n [ SQL语句 ] : ".$this->queryStr;
        }
        \Melon::debugWithTrace( $this->error );
        return $this->error;
	}


	/**
	 * 释放结果集
	 * @return [type] [description]
	 */
	public function free() {
		$this->PDOStatement = NULL;
	}
}